package org.jcnc.labreport.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jcnc.labreport.config.DashScopeConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * DashScope 服务类，用于与 DashScope API 进行交互，发送请求并返回响应结果。
 * 该服务处理异步请求、失败重试以及直接返回 API 响应的文本内容。
 */
@Service
public class DashScopeService {

    // 最大重试次数
    private static final int MAX_RETRIES = 5;
    // 请求的 URL 后缀
    private static final String REQUEST_URL_TEMPLATE = "/completion";

    private final RestTemplate restTemplate;
    private final DashScopeConfig dashScopeConfig;
    private final ObjectMapper objectMapper;

    @Autowired
    public DashScopeService(RestTemplate restTemplate, DashScopeConfig dashScopeConfig, ObjectMapper objectMapper) {
        this.restTemplate = restTemplate;
        this.dashScopeConfig = dashScopeConfig;
        this.objectMapper = objectMapper;
    }

    /**
     * 异步发送请求到 DashScope API，处理响应并返回结果。
     * 在请求失败时进行重试，最多重试 5 次。
     *
     * @param prompt          请求的提示信息
     * @param fileIds         要处理的文件 ID 列表
     * @param requestStatuses 存储请求状态的并发哈希映射
     * @return 返回操作的结果（例如：响应的文本内容或错误信息）
     */
    @Async
    public CompletableFuture<String> sendRequestAsync(String prompt, List<String> fileIds, ConcurrentHashMap<String, String> requestStatuses) {
        return CompletableFuture.supplyAsync(() -> {
            int attempts = 0;
            String result = "";

            while (attempts < MAX_RETRIES) {
                try {
                    // 更新请求状态为 "正在运行"
                    requestStatuses.put(prompt, "正在运行");

                    // 发送请求并处理响应
                    result = handleRequest(prompt, fileIds);

                    // 更新请求状态为 "结束"
                    requestStatuses.put(prompt, "结束");
                    break;  // 请求成功，退出重试循环
                } catch (Exception e) {
                    attempts++;
                    String errorMessage = String.format("请求异常: %s，重试第 %d 次", e.getMessage(), attempts);
                    requestStatuses.put(prompt, errorMessage);

                    // 如果达到最大重试次数，返回错误信息
                    if (attempts >= MAX_RETRIES) {
                        requestStatuses.put(prompt, "请求失败: " + e.getMessage());
                        result = "请求失败: " + e.getMessage();
                    }

                    try {
                        // 1秒后重试
                        Thread.sleep(1000);
                    } catch (InterruptedException interruptedException) {
                        Thread.currentThread().interrupt();
                    }
                }
            }

            return result;
        });
    }

    /**
     * 处理请求的发送和响应结果的返回。
     *
     * @param prompt  请求的提示信息
     * @param fileIds 要处理的文件 ID 列表
     * @return API 响应的文本内容
     * @throws IOException 如果发生 I/O 错误
     */
    private String handleRequest(String prompt, List<String> fileIds) throws IOException {
        String requestUrl = dashScopeConfig.getBaseUrl() + dashScopeConfig.getAppId() + REQUEST_URL_TEMPLATE;
        Map<String, Object> requestBody = buildRequestBody(prompt, fileIds);

        // 创建请求头
        HttpHeaders headers = createRequestHeaders();
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

        // 发送 HTTP 请求并接收响应
        ResponseEntity<String> response = sendHttpRequest(requestUrl, requestEntity);
        String responseBody = response.getBody();

        // 处理响应并返回文本内容
        return processResponse(responseBody);
    }

    /**
     * 创建 HTTP 请求头。
     *
     * @return 请求头
     */
    private HttpHeaders createRequestHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + dashScopeConfig.getApiKey());
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }

    /**
     * 发送 HTTP 请求并接收响应。
     *
     * @param requestUrl    请求的 URL
     * @param requestEntity 请求体
     * @return HTTP 响应
     */
    private ResponseEntity<String> sendHttpRequest(String requestUrl, HttpEntity<Map<String, Object>> requestEntity) {
        return restTemplate.exchange(requestUrl, HttpMethod.POST, requestEntity, String.class);
    }

    /**
     * 处理 API 响应并返回结果文本。
     *
     * @param responseBody API 返回的响应体
     * @return 响应的文本内容
     * @throws IOException 如果解析响应失败
     */
    private String processResponse(String responseBody) throws IOException {
        JsonNode jsonResponse = objectMapper.readTree(responseBody);
        return jsonResponse.path("output").path("text").asText();  // 返回响应中的文本内容
    }

    /**
     * 构建请求的请求体。
     *
     * @param prompt  请求的提示信息
     * @param fileIds 要处理的文件 ID 列表
     * @return 请求体的 Map 数据结构
     */
    private Map<String, Object> buildRequestBody(String prompt, List<String> fileIds) {
        Map<String, Object> input = new HashMap<>();
        input.put("prompt", prompt);

        Map<String, Object> parameters = new HashMap<>();
        Map<String, Object> ragOptions = new HashMap<>();
        ragOptions.put("pipeline_ids", dashScopeConfig.getPipelineIds());
        if (!fileIds.isEmpty()) {
            ragOptions.put("file_ids", fileIds);
        }
        parameters.put("rag_options", ragOptions);

        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("input", input);
        requestBody.put("parameters", parameters);

        return requestBody;
    }
}
